package com.sd.repay.service.impl;

import com.sd.repay.common.Constants;
import com.sd.repay.dao.BaseDao;
import com.sd.repay.pojo.PayOrder;
import com.sd.repay.pojo.RepayPlan;
import com.sd.repay.pojo.RepayPlanDetail;
import com.sd.repay.service.*;
import com.sd.repay.utils.JsonUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @author sd
 * @Description: OEM商户服务类
 * @date 2017年10月25日
 */
@Service
public class PayOrderServiceImpl implements PayOrderService {

    private static Logger log = LoggerFactory.getLogger(PayOrderServiceImpl.class);

    @Autowired
    private BaseDao baseDao;
    @Autowired
    private RepayPlanDetailService planDetailService;
    @Autowired
    private RepayPlanService planService;
    @Autowired
    private MerchantService merchantService;
    @Autowired
    private CardManageService cardManageService;


    /**
     * 新增交易订单(不支持事务，不能进行回滚了)
     *
     * @param order
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public int savePayOrder(PayOrder order) throws Exception {

        String sql = " INSERT INTO t_pay_order(merchant_no, order_no, card_no, account_no, account_name, card_type, repay_type, service, service_order_no, trans_amount, trans_fee, " +
                " trans_fee_rate, agent_fee_rate, acq_code, acq_merchant_no, acq_fee, acq_fee_rate, trans_status, is_need_profit, is_need_distrib, is_plat_profit, create_time) " +
                " VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ";
        List<Object> params = new ArrayList<>();
        params.add(order.getMerchantNo());
        params.add(order.getOrderNo());
        params.add(order.getCardNo());
        params.add(order.getAccountNo());
        params.add(order.getAccountName());
        params.add(order.getCardType());
        params.add(order.getRepayType());
        params.add(order.getService());
        params.add(order.getServiceOrderNo());
        params.add(order.getTransAmount());
        params.add(order.getTransFee());
        params.add(order.getTransFeeRate());
        params.add(order.getAgentFeeRate());
        params.add(order.getAcqCode());
        params.add(order.getAcqMerchantNo());
        params.add(order.getAcqFee());
        params.add(order.getAcqFeeRate());
        params.add(Constants.ORDER_TRANS_STATUS_INIT);
        params.add(order.getIsNeedProfit());
        params.add(order.getIsNeedDistrib());
        params.add(order.getIsPlatProfit());
        params.add(new Date());
        return baseDao.execute(sql, params.toArray());
    }

    /**
     * 根据业务类型获取订单对象
     *
     * @param service
     * @param serviceOrderNo
     * @return
     * @throws Exception
     */
    @Override
    public PayOrder getPayOrderByService(String service, String serviceOrderNo) throws Exception {

        String sql = " SELECT * FROM t_pay_order WHERE service = ? AND service_order_no = ? ORDER BY id DESC ";
        return baseDao.findFirst(PayOrder.class, sql, new Object[]{service, serviceOrderNo});
    }

    /**
     * 根据订单号获取订单对象
     *
     * @param orderNo
     * @return
     * @throws Exception
     */
    @Override
    public PayOrder getPayOrderByOrderNo(String orderNo) throws Exception {

        String sql = " SELECT * FROM t_pay_order WHERE order_no = ? ";
        return baseDao.findFirst(PayOrder.class, sql, orderNo);
    }

    /**
     * 回写订单交易信息
     *
     * @param orderNo
     * @param acqOrderNo
     * @param transTime
     * @param newTransStatus
     * @param oldTransStatus
     * @param resCode
     * @param resMsg
     * @return
     * @throws Exception
     */
    @Override
    @Transactional
    public int writeBackPayOrderInfo(String orderNo, String acqOrderNo, String transTime, String newTransStatus, String oldTransStatus, String resCode, String resMsg) throws Exception {

        List<Object> params = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        sb.append(" UPDATE t_pay_order SET acq_order_no = ?, trans_status = ?, res_code = ?, res_msg = ? ");
        params.add(acqOrderNo);
        params.add(newTransStatus);
        params.add(resCode);
        params.add(resMsg);

        if (StringUtils.isNotBlank(transTime)) {
            sb.append(" , trans_time = ? ");
            params.add(transTime);
        }

        sb.append("  WHERE order_no = ?");
        params.add(orderNo);

        if (StringUtils.isNotBlank(oldTransStatus)) {
            sb.append(" AND trans_status = ? ");
            params.add(oldTransStatus);
        }
        return baseDao.execute(sb.toString(), params.toArray());
    }

    /**
     * 修改订单通知次数
     *
     * @param orderNo
     * @return
     * @throws Exception
     */
    @Override
    @Transactional
    public int updatePayOrderNotifyNum(String orderNo) throws Exception {

        String sql = " UPDATE t_pay_order SET notify_num = notify_num + 1 WHERE order_no = ? ";
        return baseDao.execute(sql, new Object[]{orderNo});
    }

    /**
     * 修改订单通知状态
     *
     * @param orderNo
     * @param notifyStatus
     * @return
     * @throws Exception
     */
    @Override
    @Transactional
    public int updatePayOrderNotifyStatus(String orderNo, String notifyStatus) throws Exception {

        String sql = " UPDATE t_pay_order SET is_need_notify = ? WHERE order_no = ? ";
        return baseDao.execute(sql, new Object[]{notifyStatus, orderNo});
    }


    /**
     * 获取所有需要分润但是还没有分润的订单集合
     *
     * @return
     * @throws Exception
     */
    @Override
    public List<PayOrder> getUnProfitPayOrder() throws Exception {

        String sql = " SELECT * FROM t_pay_order WHERE trans_status = ? AND is_need_profit = '1' AND have_cal_profit = '0' ORDER BY create_time ASC";
        return baseDao.findList(PayOrder.class, sql, Constants.ORDER_TRANS_STATUS_SUCCESS);
    }

    /**
     * 获取30天内10分钟前创建的未知，交易中状态的所有订单
     *
     * @return
     * @throws Exception
     */
    @Override
    public List<PayOrder> getUnEndStatusPayOrder() throws Exception {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date now = new Date();

        Calendar nowCal = Calendar.getInstance();
        nowCal.setTime(now);
        nowCal.add(Calendar.DAY_OF_YEAR, -30);
        String beginTime = sdf.format(nowCal.getTime()) + " 00:00:00";

        nowCal = Calendar.getInstance();
        nowCal.setTime(now);
        nowCal.add(Calendar.MINUTE, -10);
        sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String endTime = sdf.format(nowCal.getTime());

        String sql = " SELECT * FROM t_pay_order WHERE trans_status IN (?, ?) AND create_time >= ? AND create_time < ? ";
        return baseDao.findList(PayOrder.class, sql, new Object[]{Constants.ORDER_TRANS_STATUS_IN, Constants.ORDER_TRANS_STATUS_UNKNOW, beginTime, endTime});
    }

    /**
     * 查询需要30天内10分钟前创建的需要通知的交易订单记录
     *
     * @return
     * @throws Exception
     */
    @Override
    public List<PayOrder> getNeedNotifyPayOrder() throws Exception {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date now = new Date();

        Calendar nowCal = Calendar.getInstance();
        nowCal.setTime(now);
        nowCal.add(Calendar.DAY_OF_YEAR, -30);
        String beginTime = sdf.format(nowCal.getTime()) + " 00:00:00";

        nowCal = Calendar.getInstance();
        nowCal.setTime(now);
        nowCal.add(Calendar.MINUTE, -10);
        sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String endTime = sdf.format(nowCal.getTime());

        String sql = "SELECT * FROM t_pay_order WHERE trans_status IN (?,?) AND is_need_notify = ? AND create_time >= ? AND create_time < ?";
        return baseDao.findList(PayOrder.class, sql, new Object[]{Constants.ORDER_TRANS_STATUS_SUCCESS, Constants.ORDER_TRANS_STATUS_FAIL, Constants.IS_NEED_NOTIFY, beginTime, endTime});
    }

    /**
     * 根据卡片编号获取未知状态的交易
     *
     * @param cardNo
     * @return
     * @throws Exception
     */
    @Override
    public List<PayOrder> getUnEndStatusPayOrderByCardNo(String cardNo) throws Exception {

        String sql = "SELECT * FROM t_pay_order WHERE trans_status IN (?,?) AND card_no = ? ";
        return baseDao.findList(PayOrder.class, sql, new Object[]{Constants.ORDER_TRANS_STATUS_IN, Constants.ORDER_TRANS_STATUS_UNKNOW, cardNo});
    }

    /**
     * 获取需要进行代理商分润的交易订单
     *
     * @return
     * @throws Exception
     */
    @Override
    public List<PayOrder> getSuccToProfitOrder() throws Exception {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date now = new Date();

        Calendar nowCal = Calendar.getInstance();
        nowCal.setTime(now);
        nowCal.add(Calendar.DAY_OF_YEAR, -30);
        String beginTime = sdf.format(nowCal.getTime()) + " 00:00:00";

        String sql = "SELECT order_no FROM t_pay_order WHERE trans_status = ? AND is_need_profit = ? AND have_profit = ? AND create_time >= ?";
        return baseDao.findList(PayOrder.class, sql, new Object[]{Constants.ORDER_TRANS_STATUS_SUCCESS, Constants.IS_NEED_PROFIT, Constants.HAVE_NOT_PROFIT, beginTime});
    }

    /**
     * 获取需要进行商户分销的交易订单
     *
     * @return
     * @throws Exception
     */
    @Override
    public List<PayOrder> getSuccToDistribOrder() throws Exception {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date now = new Date();

        Calendar nowCal = Calendar.getInstance();
        nowCal.setTime(now);
        nowCal.add(Calendar.DAY_OF_YEAR, -30);
        String beginTime = sdf.format(nowCal.getTime()) + " 00:00:00";

        String sql = "SELECT order_no FROM t_pay_order WHERE trans_status = ? AND is_need_distrib = ? AND have_distrib = ? AND create_time >= ?";
        return baseDao.findList(PayOrder.class, sql, new Object[]{Constants.ORDER_TRANS_STATUS_SUCCESS, Constants.IS_NEED_DISTRIB, Constants.HAVE_NOT_DISTRIB, beginTime});
    }

    /**
     * 获取需要进行平台收益的交易订单
     *
     * @return
     * @throws Exception
     */
    @Override
    public List<PayOrder> getSuccToPlatProfitOrder() throws Exception {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date now = new Date();

        Calendar nowCal = Calendar.getInstance();
        nowCal.setTime(now);
        nowCal.add(Calendar.DAY_OF_YEAR, -30);
        String beginTime = sdf.format(nowCal.getTime()) + " 00:00:00";

        String sql = "SELECT order_no FROM t_pay_order WHERE trans_status = ? AND is_plat_profit = ? AND have_plat_profit = ? AND create_time >= ?";
        return baseDao.findList(PayOrder.class, sql, new Object[]{Constants.ORDER_TRANS_STATUS_SUCCESS, Constants.IS_PLAT_PROFIT, Constants.HAVE_NOT_PLAT_PROFIT, beginTime});
    }

    /**
     * 修改订单分润状态
     *
     * @param orderNo
     * @return
     * @throws Exception
     */
    @Override
    @Transactional
    public int updatePayOrderProfitStatus(String orderNo) throws Exception {

        String sql = " UPDATE t_pay_order SET have_profit = ? WHERE order_no = ? AND is_need_profit = ? AND have_profit = ? ";
        return baseDao.execute(sql, new Object[]{Constants.HAVE_PROFIT, orderNo, Constants.IS_NEED_PROFIT, Constants.HAVE_NOT_PROFIT});
    }

    /**
     * 修改订单分销状态
     *
     * @param orderNo
     * @return
     * @throws Exception
     */
    @Override
    @Transactional
    public int updatePayOrderDistribStatus(String orderNo) throws Exception {

        String sql = " UPDATE t_pay_order SET have_distrib = ? WHERE order_no = ? AND is_need_distrib = ? AND have_distrib = ? ";
        return baseDao.execute(sql, new Object[]{Constants.HAVE_DISTRIB, orderNo, Constants.IS_NEED_DISTRIB, Constants.HAVE_NOT_DISTRIB});
    }

    /**
     * 修改订单平台收益状态
     *
     * @param orderNo
     * @return
     * @throws Exception
     */
    @Override
    @Transactional
    public int updatePayOrderPlatProfitStatus(String orderNo) throws Exception {

        String sql = " UPDATE t_pay_order SET have_plat_profit = ? WHERE order_no = ? AND is_plat_profit = ? AND have_plat_profit = ? ";
        return baseDao.execute(sql, new Object[]{Constants.HAVE_PLAT_PROFIT, orderNo, Constants.IS_PLAT_PROFIT, Constants.HAVE_NOT_PLAT_PROFIT});
    }

    /**
     * 订单回调业务
     *
     * @param orderNo
     * @return
     * @throws Exception
     */
    @Override
    @Transactional
    public String payOrderCallBack(String orderNo) throws Exception {

        log.info("交易订单号" + orderNo + "回调业务处理开始");

        PayOrder order = getPayOrderByOrderNo(orderNo);
        if (order == null) {
            log.info("交易订单号" + orderNo + "错误信息：订单不存在");
            return "FAIL";
        }

        String acqPayToken = order.getAcqPayToken();
        String merchantNo = order.getMerchantNo();
        String accountNo = order.getAccountNo();
        String acqCode = order.getAcqCode();
        String transStatus = order.getTransStatus();
        String service = order.getService();
        String serviceOrderNo = order.getServiceOrderNo();
        BigDecimal transAmount = order.getTransAmount();
        String resMsg = order.getResMsg();

        //交易成功
        if (Constants.ORDER_TRANS_STATUS_SUCCESS.equals(transStatus)) {

            if (Constants.PAY_ORDER_SERVICE_REPAY.equals(service)) {

                resMsg = StringUtils.isBlank(resMsg) ? "支付成功" : resMsg;
                //如果是还款计划消费
                RepayPlanDetail planDetail = planDetailService.getDetailByPlanNo(serviceOrderNo);
                log.info("计划明细编号：" + serviceOrderNo + "对应的计划明细对象为：" + JsonUtil.objectToJson(planDetail));
                if (null == planDetail) {
                    return "FAIL";
                }

                RepayPlan repayPlan = planService.getRepayPlanByBatchNo(planDetail.getBatchNo());
                log.info("计划明细编号：" + serviceOrderNo + "对应的计划对象为：" + JsonUtil.objectToJson(repayPlan));
                if (null == repayPlan) {
                    return "FAIL";
                }

                String batchNo = repayPlan.getBatchNo();
                String repayType = repayPlan.getRepayType();
                int planIndex = planDetail.getPlanIndex();

                int count = planDetailService.updateDetailStatus(serviceOrderNo, Constants.PLAN_DETAIL_STATUS_SUCCESS, null, "订单回调：" + resMsg);
                log.info("更改计划明细编号：" + serviceOrderNo + "状态为成功影响的行数为" + count);
                if (count > 0) {

                    //判断是否是第一笔交易，如果是，则该计划也需要改为还款中
                    if (planIndex == 1) {
                        // 第一笔交易失败，计划也要改为还款中状态
                        count = planService.updateRepayPlanStatus(batchNo, Constants.PLAN_STATUS_IN_EXECUTE, null, "");
                        log.info("计划批次号：" + batchNo + "对应第一笔交易回调成功，故将此计划状态改为还款中影响的行数：" + count);
                    }

                    //判断是否是最后一笔，如果是最后一笔，就标识这个还款计划已完成
                    boolean isLast = planDetailService.isLastIndexDetail(batchNo, planIndex);
                    if (isLast) {
                        log.info("计划明细编号：" + serviceOrderNo + "是最后一笔还款明细，且执行成功，故标识整个还款成功");
                        count = planService.updateRepayPlanStatus(batchNo, Constants.PLAN_STATUS_SUCCESS, Constants.PLAN_STATUS_IN_EXECUTE, "还款完成");
                        log.info("更改计划批次号：" + batchNo + "为还款成功状态影响的行数" + count);
                    }
                }
            }
            //交易失败
        } else if (Constants.ORDER_TRANS_STATUS_FAIL.equals(transStatus)) {

            if (Constants.PAY_ORDER_SERVICE_REPAY.equals(service)) {

                RepayPlanDetail planDetail = planDetailService.getDetailByPlanNo(serviceOrderNo);
                log.info("计划明细编号：" + serviceOrderNo + "对应的计划明细对象为：" + JsonUtil.objectToJson(planDetail));
                if (null == planDetail) {
                    return "FAIL";
                }

                RepayPlan repayPlan = planService.getRepayPlanByBatchNo(planDetail.getBatchNo());
                log.info("计划明细编号：" + serviceOrderNo + "对应的计划对象为：" + JsonUtil.objectToJson(repayPlan));
                if (null == repayPlan) {
                    return "FAIL";
                }

                String batchNo = repayPlan.getBatchNo();
                String repayType = repayPlan.getRepayType();
                int planIndex = planDetail.getPlanIndex();
                int planCount = planDetail.getPlanCount();

                int count = planDetailService.updateDetailStatus(serviceOrderNo, Constants.PLAN_DETAIL_STATUS_FAIL, null, "订单回调：" + resMsg);
                log.info("更改计划明细编号：" + serviceOrderNo + "状态为失败影响的行数为" + count);
                if (count > 0) {
                    //判断计划明细是否是第一笔交易，如果是，则该计划也需要改为失败
                    if (planIndex == 1) {
                        // 第一笔交易失败，计划也要改为失败状态
                        count = planService.updateRepayPlanStatus(batchNo, Constants.PLAN_STATUS_FAIL, Constants.PLAN_STATUS_UN_EXECUTE, "第一笔交易失败，计划失败");
                        log.info("计划批次号：" + batchNo + "对应第一笔交易回调失败，故将次计划状态改为失败影响的行数：" + count);
                    }

                    //判断此明细执行次数是否达到最大值，如果已到，则此还款计划直接失败
                    if (Constants.PLAN_MAX_EXECUTE_COUNT == planCount) {
                        log.info("明细编号：" + serviceOrderNo + "执行次数已经达到" + planCount + "次，且操作次数已到" + Constants.PLAN_MAX_EXECUTE_COUNT + "" +
                                "次，故将此还款计划状态直接改为失败");
                        count = planService.updateRepayPlanStatus(batchNo, Constants.PLAN_STATUS_FAIL, Constants.PLAN_STATUS_IN_EXECUTE, "还款失败");
                        log.info("更改计划批次号：" + batchNo + "为失败状态影响的行数" + count);

                    } else if (Constants.PLAN_EXPECT_STATUS_STOP.equals(repayPlan.getExpectStatus())) {
                        //如果没有达到3次，判断此计划是否已预处理，如果是，则直接改为终止状态
                        log.info("计划批次号：" + batchNo + "已预处理，故直接改其批次状态为终止状态");
                        count = planService.updateRepayPlanStatus(batchNo, Constants.PLAN_STATUS_STOP, Constants.PLAN_STATUS_IN_EXECUTE, "用户终止");
                        log.info("更改计划批次号：" + batchNo + "为终止状态影响的行数" + count);
                    }
                }
            }
        }
        log.info("交易订单[{}]回调业务处理结束", orderNo);

        return "SUCCESS";
    }

}